package buco.integrity.osgi;

import java.util.*;

import buco.core.api.*;

public class DependencyIntegrity extends IntegrityCheck {
	
	@Override
	public void checkIntegrity(Bundle bundle, IntegrityReport report) {
		checkBundle(bundle, report); 	
	}
	
	private void checkBundle(Bundle bundle, IntegrityReport report) {
		// Get the connections that go out from this bundle 
		List<BundleWire> wires = this.composition.getOutgoingWires(bundle, true);
		// Get the connected bundles 
		ArrayList<Bundle> candidates = new ArrayList<Bundle>(); 
		candidates.add(bundle);
		for(BundleWire wire : wires) {
			candidates.add(wire.getTo()); 
		}
		// Imports and required bundles must be available 
		for(Requirement req : bundle.getRequirements()) {
			if(req instanceof ImportPackageRequirement) {
				ImportPackageRequirement ipr = (ImportPackageRequirement) req;
				if(ipr.isSystemPackage()) {
					// System packages are always resolved and are disregarded in this check.
					continue;
				}					
			}
			
			if(!isRequirementSatisfied(candidates, req)) {
				report.warn(makeWarning(req));
			}
		}
	}
	
	private String makeWarning(Requirement req) {
		if(req instanceof ImportPackageRequirement) {
			ImportPackageRequirement ipr = (ImportPackageRequirement) req; 
			String pack = ipr.getPackageName(); 
			if(ipr.getPackageVersionRange() != null) {
				pack += ";version=" + ipr.getPackageVersionRange().toString();
			}
			return String.format("Imported package %s could not be resolved.", pack);  
		}
		else if(req instanceof RequireBundleRequirement) {
			RequireBundleRequirement rbr = (RequireBundleRequirement) req;
			return String.format("Required bundle %s is missing.", rbr.getBundleSymbolicName()); 			
		}
		return null; 
	}
	
	private boolean isRequirementSatisfied(List<Bundle> candidates, Requirement req) {
		for(Bundle candidate : candidates) {
			if(candidate.satisfiesRequirement(req))
				return true; 
		}
		return false; 
	}

}
